package org.omnifaces.converter;

import org.omnifaces.util.Messages;
import org.omnifaces.util.selectitems.SelectItemsCollector;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.faces.convert.FacesConverter;
import javax.faces.model.SelectItem;
import java.util.List;

@FacesConverter("omnifaces.SelectItemsIndexConverter")
public class SelectItemsIndexConverter implements Converter {

    private static final String SELECT_ITEMS_LIST_NULL_ERROR = "Could not determine select items list for component {0}";
    private static final String SELECT_ITEMS_LIST_INDEX_ERROR = "Could not determine index for value {0} in component {1}";
    private static final String NO_SELECT_ITEM_VALUE_FOUND_ERROR = "No matching select item entry was found for object {0} in component {1}";
    private static final String GET_AS_OBJECT_ERROR = "Could not convert value {0} for component {1}";

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String valueToConvert) {
        final List<SelectItem> selectItemList = SelectItemsCollector.collectFromParent(context, component);
        if (selectItemList == null) {
            throw new ConverterException(Messages.createError(SELECT_ITEMS_LIST_NULL_ERROR, component.getClientId()));
        }
        try {
            return selectItemList.get(Integer.parseInt(valueToConvert)).getValue();
        } catch (NumberFormatException nfe) {
            throw new ConverterException(Messages.createError(SELECT_ITEMS_LIST_INDEX_ERROR, valueToConvert, component.getClientId()), nfe);
        } catch (Exception nfe) {
            throw new ConverterException(Messages.createError(GET_AS_OBJECT_ERROR, valueToConvert, component.getClientId()), nfe);
        }
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object objectToConvert) {
        final List<SelectItem> selectItemList = SelectItemsCollector.collectFromParent(context, component);
        if (selectItemList == null) {
            throw new ConverterException(Messages.createError(SELECT_ITEMS_LIST_NULL_ERROR, component.getClientId()));
        }
        for (int i = 0; i < selectItemList.size(); i++) {
            SelectItem aSelectItem = selectItemList.get(i);
            Object aSelectItemValueObject = aSelectItem.getValue();
            if (bothNull(objectToConvert, aSelectItemValueObject) || bothEquals(objectToConvert, aSelectItemValueObject)) {
                return Integer.toString(i);
            }
        }
        throw new ConverterException(Messages.createError(NO_SELECT_ITEM_VALUE_FOUND_ERROR, objectToConvert, component.getClientId()));
    }

    private boolean bothEquals(Object objectToConvert, Object itemValueObject) {
        return (objectToConvert != null && objectToConvert.equals(itemValueObject));
    }

    private boolean bothNull(Object objectToConvert, Object itemValueObject) {
        return (objectToConvert == null && itemValueObject == null);
    }
}

